package com.jplus.framework.aop;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jplus.framework.AppConstant;
import com.jplus.framework.InstanceFactory;
import com.jplus.framework.aop.annotation.Aspect;
import com.jplus.framework.aop.annotation.AspectOrder;
import com.jplus.framework.aop.proxy.Proxy;
import com.jplus.framework.aop.proxy.ProxyManager;
import com.jplus.framework.bean.BeanHandle;
import com.jplus.framework.core.fault.InitializationError;
import com.jplus.framework.db.TransactionProxy;
import com.jplus.framework.db.annotation.Transaction;
import com.jplus.framework.plugin.PluginProxy;
import com.jplus.framework.util.ClassUtil;
import com.jplus.framework.util.FormatUtil;

/**
 * 初始化 AOP 框架
 *
 * @author huangyong
 * @author yuanqy
 */
public class AopHandle {
	private static Logger logger = LoggerFactory.getLogger(AopHandle.class);
	/**
	 * 获取 ClassScanner
	 */

	static {
		try {
			// 创建 Proxy Map（用于 存放代理类 与 目标类列表 的映射关系）
			Map<Class<?>, List<Class<?>>> proxyMap = createProxyMap();
			// 创建 Target Map（用于 存放目标类 与 代理类列表 的映射关系）
			Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
			// 遍历 Target Map
			for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
				// 分别获取 map 中的 key 与 value
				Class<?> targetClass = targetEntry.getKey();
				List<Proxy> proxyList = targetEntry.getValue();
				// 创建代理实例
				Object proxyInstance = ProxyManager.createProxy(targetClass, proxyList,null);
				// 用代理实例覆盖目标实例，并放入 Bean 容器中
				logger.info("\t[aop]{}", targetClass);
				BeanHandle.setTempBean(targetClass, proxyInstance);
			}
		} catch (Exception e) {
			throw new InitializationError("初始化 AopHandle 出错！", e);
		}
	}

	private static Map<Class<?>, List<Class<?>>> createProxyMap() throws Exception {
		Map<Class<?>, List<Class<?>>> proxyMap = new LinkedHashMap<Class<?>, List<Class<?>>>();
		// 添加相关代理
		addPluginProxy(proxyMap); // 插件代理
		addAspectProxy(proxyMap); // 切面代理
		addTransactionProxy(proxyMap); // 事务代理
		return proxyMap;
	}

	private static void addAspectProxy(Map<Class<?>, List<Class<?>>> proxyMap) throws Exception {
		// 获取切面类（所有继承于 BaseAspect 的类）
		List<Class<?>> aspectProxyClassList = new ArrayList<Class<?>>();
		for (Class<?> cla : BeanHandle.beanSet) {
			if (AspectProxy.class.isAssignableFrom(cla))
				aspectProxyClassList.add(cla);
		}
		// 排序切面类
		sortAspectProxyClassList(aspectProxyClassList);
		// 遍历切面类
		for (Class<?> aspectProxyClass : aspectProxyClassList) {
			// 判断 Aspect 注解是否存在
			if (aspectProxyClass.isAnnotationPresent(Aspect.class)) {
				// 获取 Aspect 注解
				Aspect aspect = aspectProxyClass.getAnnotation(Aspect.class);
				// 创建目标类列表
				List<Class<?>> targetList = createTargetList(aspect);
				// 初始化 Proxy Map
				proxyMap.put(aspectProxyClass, targetList);
			}
		}
	}

	private static void addTransactionProxy(Map<Class<?>, List<Class<?>>> proxyMap) {
		List<Class<?>> list = new ArrayList<Class<?>>();
		for (Class<?> cls : BeanHandle.beanSet) {
			if (cls.isAnnotationPresent(Transaction.class)) {
				list.add(cls);
				continue;
			}
			Method[] ms = cls.getMethods();
			for (Method m : ms) {
				if (m.isAnnotationPresent(Transaction.class)) {
					list.add(cls);
					break;
				}
			}
		}
		proxyMap.put(TransactionProxy.class, list);
	}

	private static void sortAspectProxyClassList(List<Class<?>> proxyClassList) {
		// 排序代理类列表
		Collections.sort(proxyClassList, new Comparator<Class<?>>() {
			@Override
			public int compare(Class<?> aspect1, Class<?> aspect2) {
				if (aspect1.isAnnotationPresent(AspectOrder.class) || aspect2.isAnnotationPresent(AspectOrder.class)) {
					// 若有 Order 注解，则优先比较（序号的值越小越靠前）
					if (aspect1.isAnnotationPresent(AspectOrder.class)) {
						return getOrderValue(aspect1) - getOrderValue(aspect2);
					} else {
						return getOrderValue(aspect2) - getOrderValue(aspect1);
					}
				} else {
					// 若无 Order 注解，则比较类名（按字母顺序升序排列）
					return aspect1.hashCode() - aspect2.hashCode();
				}
			}

			private int getOrderValue(Class<?> aspect) {
				return aspect.getAnnotation(AspectOrder.class) != null ? aspect.getAnnotation(AspectOrder.class).value() : 0;
			}
		});
	}

	private static List<Class<?>> createTargetList(Aspect aspect) throws Exception {
		List<Class<?>> targetList = new ArrayList<Class<?>>();
		// 获取 Aspect 注解的相关属性
		String pkg = aspect.pkg();
		String cls = aspect.cls();
		Class<? extends Annotation> annotation = aspect.annotation();
		// 若包名不为空，则需进一步判断类名是否为空
		if (!FormatUtil.isEmpty(pkg)) {
			if (!FormatUtil.isEmpty(cls)) {
				// 若类名不为空，则仅添加该类
				targetList.add(ClassUtil.loadClass(pkg + "." + cls, false));
			} else {
				// 若注解不为空且不是 Aspect 注解，则添加指定包名下带有该注解的所有类
				if (annotation != null && !annotation.equals(Aspect.class)) {
					targetList.addAll(InstanceFactory.getClassScanner().getListByAnnotation(pkg, annotation, false));
				} else {
					// 否则添加该包名下所有类
					targetList.addAll(InstanceFactory.getClassScanner().getList(pkg));
				}
			}
		} else {
			// 若注解不为空且不是 Aspect 注解，则添加应用包名下带有该注解的所有类
			if (annotation != null && !annotation.equals(Aspect.class)) {
				targetList.addAll(InstanceFactory.getClassScanner().getListByAnnotation(AppConstant.CONFIG.AppScanPKG.getValue(), annotation, false));
			}
		}
		return targetList;
	}

	private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, List<Class<?>>> proxyMap) throws Exception {
		Map<Class<?>, List<Proxy>> targetMap = new HashMap<Class<?>, List<Proxy>>();
		// 遍历 Proxy Map
		for (Map.Entry<Class<?>, List<Class<?>>> proxyEntry : proxyMap.entrySet()) {
			// 分别获取 map 中的 key 与 value
			Class<?> proxyClass = proxyEntry.getKey();
			List<Class<?>> targetList = proxyEntry.getValue();
			// 遍历目标类列表
			for (Class<?> targetClass : targetList) {
				// 创建代理类（切面类）实例
				Proxy baseAspect = (Proxy) proxyClass.newInstance();
				// 初始化 Target Map
				if (targetMap.containsKey(targetClass)) {
					targetMap.get(targetClass).add(baseAspect);
				} else {
					List<Proxy> baseAspectList = new ArrayList<Proxy>();
					baseAspectList.add(baseAspect);
					targetMap.put(targetClass, baseAspectList);
				}
			}
		}
		return targetMap;
	}

	private static void addPluginProxy(Map<Class<?>, List<Class<?>>> proxyMap) throws Exception {
		for (Class<?> cls : BeanHandle.beanSet) {
			if (PluginProxy.class.isAssignableFrom(cls) && !PluginProxy.class.equals(cls)) {
				// 创建插件代理类实例
				PluginProxy pluginProxy = (PluginProxy) cls.newInstance();
				// 将插件代理类及其所对应的目标类列表放入 Proxy Map 中
				proxyMap.put(cls, pluginProxy.getTargetClassList());
			}
		}
	}
}
